//  两个单词用大大，三个单词用小大小
/// 这个类具体像怎么实现，就是提供给connection进行读取和存放数据的一个缓冲区，并且提供各种操作该缓冲区的接口，内部使用两个index来维护读位置，写位置
/// 首先需要一个vector<char>的一个缓冲区
#include <vector>
#include <iostream>
#include <cassert>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <functional>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/epoll.h>
// 这里外部数据拷贝到内部数据主要用copy方法，这个方法就要获取被拷贝前数据的地址，数据拷贝到哪里的地址，所有内部buffer要提供当前的写，读实际地址

#define MUDUO_BUFFER 4096

#define INF 0
#define DBG 1
#define ERR 2
#define LOG_LEVEL INF
static int log = 0;

#define LOG(level, format, ...)                                                                                                  \
    do                                                                                                                           \
    {                                                                                                                            \
        if (level < LOG_LEVEL)                                                                                                   \
            break;                                                                                                               \
        time_t t = time(NULL);                                                                                                   \
        struct tm *ltm = localtime(&t);                                                                                          \
        char tmp[32] = {0};                                                                                                      \
        strftime(tmp, 31, "%Y-%m-%d %H:%M:%S", ltm);                                                                             \
        log++;                                                                                                                   \
        fprintf(stdout, "[%04d %p %s %s:%d] " format "\n", log, (void *)pthread_self(), tmp, __FILE__, __LINE__, ##__VA_ARGS__); \
    } while (0)

// "ss: %s" -》将##__VA_ARGS__按照format "\n"格式输出     输出到输出流就是ss:字符串这种格式    格式化输出到输出流中
// 前面的一直到"n"表示格式化输出的格式
#define INF_LOG(format, ...) LOG(INF, format, ##__VA_ARGS__)
#define DBG_LOG(format, ...) LOG(DBG, format, ##__VA_ARGS__)
#define ERR_LOG(format, ...) LOG(ERR, format, ##__VA_ARGS__)
// 这个宏接受三个参数：日志级别（level）、日志格式（format）和可变参数列表（__VA_ARGS__）

namespace muduo
{
    class Buffer
    {
    public:
        Buffer() : _buffer(MUDUO_BUFFER), _readr_index(0), _writer_index(0)
        {
        }
        char *readPosition() // 当前读位置
        {
            char *pos = &(*_buffer.begin());
            return (pos + _readr_index);
        }

        char *writePosition() // 当前写位置
        {
            char *pos = &(*_buffer.begin());
            return (pos + _writer_index);
        }

        // 获取缓冲区末尾空闲空间大小--写偏移之后的空闲空间, 总体空间大小减去写偏移
        u_int64_t getBufferTailSize() { return _buffer.size() - _writer_index; }

        // 获取缓冲区起始空闲空间大小--读偏移之前的空闲空间
        u_int64_t getBufferHeadSize() { return _readr_index; }
        // 获取当前缓冲区无效数据区域
        u_int64_t getAllBufferFreeSize() { return getBufferHeadSize() + getBufferTailSize(); }

        // 获取可读数据大小 = 写偏移 - 读偏移
        u_int64_t ReadAbleSize() { return _writer_index - _readr_index; }

        // 将读偏移向后移动
        /*void MoveReadOffset(u_int64_t len)
        {
            _readr_index += len;
            return;
        }*/
        void MoveReadOffset(u_int64_t len)
        {
            if (len == 0)
                return;
            // 向后移动的大小，必须小于可读数据大小
            assert(len <= ReadAbleSize());
            _readr_index += len;
        }

        // 将写偏移向后移动
        void MoveWriteOffset(u_int64_t len)
        {
            // 这里规定如果直接MoveWriteOffset，如果len大于后置空闲空间就返回，只有在EnsureWriteSpace中才进行扩容操作
            if (len == 0)
                return;
            assert(len <= getBufferTailSize());
            _writer_index += len;
            return;
        }

        // 确保可写空间足够（整体空闲空间够了就移动数据，否则就扩容）
        void EnsureWriteSpace(u_int64_t len)
        {
            if (len <= getBufferTailSize())
                return;
            if (len <= getAllBufferFreeSize())
            {
                u_int64_t rsz = ReadAbleSize(); // 可读数据大小
                std::copy(readPosition(), readPosition() + rsz, (char *)(&*_buffer.begin()));
                _readr_index = 0;
                _writer_index = _readr_index + rsz;
            }
            else
            {
                // 此时需要扩容,库容的大小，需要为
                _buffer.resize(len * 2 + _buffer.size());
                _writer_index += len;
            }
        }
        // 数据进行写入
        void Write(const void *data, u_int64_t len)
        {
            EnsureWriteSpace(len);                                                    // 先确保数据可以写入
            std::copy((const char *)data, (const char *)data + len, writePosition()); // 将data中数据拷贝到指定的写位置
        }

        void WriteAndPush(const void *data, u_int64_t len)
        {
            Write(data, len);
            MoveWriteOffset(len);
        }

        void WriteString(const std::string &str)
        {
            Write(str.c_str(), str.size());
        }

        void WriteStringAndPush(const std::string &str)
        {
            WriteAndPush(str.c_str(), str.size());
        }

        void WriteBuffer(Buffer &buffer)
        {
            Write(buffer.readPosition(), buffer.getAllBufferFreeSize());
        }

        void WriteBufferAndPush(Buffer &buffer)
        {
            WriteAndPush(buffer.readPosition(), buffer.getAllBufferFreeSize());
        }

        void Read(void *buf, u_int64_t len) // const &是输入   &是输入输出   *是输出
        {
            // 将指定长度的内容读到传入的缓冲区中，读入指定len字节
            if (len == 0)
                return;
            assert(len <= ReadAbleSize());
            std::copy(readPosition(), readPosition() + len, (char *)buf); // 直接将数据拷贝到buf中
            return;
        }

        void ReadAndPop(void *buf, u_int64_t len)
        {
            Read(buf, len);
            MoveReadOffset(len);
        }

        std::string ReadAsString(u_int64_t len)
        {
            assert(len <= ReadAbleSize());
            std::string str;
            str.resize(len);
            Read((void *)str.c_str(), len);
            return str;
        }

        std::string ReadAsStringAndPop(u_int64_t len)
        {
            assert(len <= ReadAbleSize());
            std::string str;
            str.resize(len);
            ReadAndPop((void *)str.c_str(), len);
            return str;
        }

        char *FindCRLF()
        {
            // 这里"\r\n"查找到'\n'就够了
            void *pos = memchr(readPosition(), '\n', ReadAbleSize());
            if ((char *)pos == nullptr)
                return nullptr;
            return (char *)pos;
        }

        std::string GetLine()
        {
            char *pos = FindCRLF();
            if (pos == nullptr)
                return std::string("");
            return ReadAsString(pos - readPosition() + 1);
        }

        std::string GetLineAndPop()
        {
            char *pos = FindCRLF();
            if (pos == nullptr)
                return std::string("");
            return ReadAsStringAndPop(pos - readPosition() + 1);
        }

        bool ifSatisfyint32_t()
        {
            int size = ReadAbleSize();
            if (size == 32)
                return true;
            else
                return false;
        }

        void clear()
        {
            _readr_index = 0;
            _writer_index = 0;
        }

        ~Buffer() {}

    private:
        std::vector<char> _buffer;
        u_int64_t _readr_index;  // 还未读取的第一个有效位置
        u_int64_t _writer_index; // 当前写入位置，有效数据是前一个
    };

#define MAX_LISTEN 1024

    /// 这个模型是用来提供套接字以及套接字对应的操作的
    class Socket
    {
    public:
        Socket() : _sockfd(1)
        {
        }
        Socket(int sockfd) : _sockfd(sockfd)
        {
        }
        // 创建套接字
        bool Create()
        {
            // int socket(int domain, int type, int protocol)
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                DBG_LOG("SOCKET ERROR");
                return false;
            }
            return true;
        }
        // 绑定地址信息
        bool Bind(const std::string &ip, u_int16_t port)
        {
            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);
            // 处理0.0.0.0地址的特殊情况
            if (ip == "0.0.0.0")
            {
                addr.sin_addr.s_addr = INADDR_ANY;
            }
            else
            {
                addr.sin_addr.s_addr = inet_addr(ip.c_str());
            }
            socklen_t len = sizeof(addr);

            int ret = ::bind(_sockfd, (sockaddr *)(&addr), len);
            if (ret < 0)
            {
                ERR_LOG("BIND ERROR: %s", strerror(errno));
                return false;
            }
            DBG_LOG("Bind success to %s:%d", ip.c_str(), port);
            return true;
        }
        // 开始监听
        bool Listen(int backlog = 1024)
        {
            // int listen(int backlog)
            int ret = ::listen(_sockfd, backlog);
            if (ret < 0)
            {
                ERR_LOG("LISTEN ERROR: %s", strerror(errno));
                return false;
            }
            DBG_LOG("Listen success with backlog: %d", backlog);
            return true;
        }
        // 向服务器发起连接
        bool Connect(const std::string &ip, u_int16_t port)
        {
            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);
            addr.sin_addr.s_addr = inet_addr(ip.c_str());
            socklen_t len = sizeof(struct sockaddr_in);
            // int connect(int sockfd, struct sockaddr*addr, socklen_t len);
            DBG_LOG("sockfd: %d", _sockfd);
            int ret = connect(_sockfd, (struct sockaddr *)&addr, len);
            if (ret < 0)
            {
                ERR_LOG("CONNECT: %d", ret);
                ERR_LOG("CONNECT SERVER FAILED!");
                return false;
            }
            DBG_LOG("connect success");
            return true;
        }
        // 获取新连接
        int Accept()
        {
            // int accept(int sockfd, struct sockaddr *addr, socklen_t *len);
            struct sockaddr_in addr;
            socklen_t len = sizeof(addr);

            int sockfd = ::accept(_sockfd, (sockaddr *)(&addr), &len);
            if (sockfd < 0)
            {
                DBG_LOG("Accept ERROR");
                abort();
            }
            return sockfd;
        }
        // 接收数据
        ssize_t Recv(void *buf, size_t len, int flag = 0)
        {
            // ssize_t recv(int sockfd, void *buf, size_t len, int flag);
            DBG_LOG("Recv");
            ssize_t ret = ::recv(_sockfd, buf, len, flag);
            if (ret <= 0)
            {
                DBG_LOG("ret: %ld", ret);
                if (errno == EINTR || errno == EWOULDBLOCK)
                {
                    return 0;
                }
                else
                {
                    ERR_LOG("RECV FAILED");
                    return -1;
                }
            }
            DBG_LOG("ret: %ld", ret);
            return ret;
        }
        ssize_t NonBlockRecv(void *buf, size_t len) // 进行非阻塞式读取
        {
            return Recv(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT表示非阻塞
        }
        // 发送数据
        ssize_t Send(const void *buf, size_t len, int flag = 0)
        {
            // ssize_t send(int sockfd, void *data, size_t len, int flag);
            ssize_t ret = send(_sockfd, buf, len, flag);
            if (ret < 0)
            {
                if (errno == EAGAIN || errno == EINTR)
                {
                    return 0;
                }
                ERR_LOG("SOCKET SEND FAILED!!");
                return -1;
            }
            DBG_LOG("send success ret: %ld", ret);
            return ret; // 实际发送的数据长度
        }
        ssize_t NonBlockSend(void *buf, size_t len)
        {
            return Send(buf, len, MSG_DONTWAIT);
        }
        // 关闭套接字
        void Close()
        {
            ::close(_sockfd); // 关闭套接字
        }
        // 创建一个服务端连接  服务端直接调用这个创建一个监听套接字用来进行通信
        bool CreateServer(u_int16_t port, const std::string &ip = "0.0.0.0", bool block_flag = false) // 默认是false
        {
            // 1. 创建套接字，2. 绑定地址，3. 开始监听，4. 设置非阻塞， 5. 启动地址重用
            if (!Create())
                return false;
            if (!Bind(ip, port))
                return false;
            if (!Listen())
                return false;
            if (block_flag)
                NonBlock();
            ReuseAddress();
            return true;
        }
        // 创建一个客户端连接  客户端直接调用这个创建一个普通网络套接字用来进行通信
        bool CreateClient(u_int16_t port, const std::string &ip)
        {
            // 1. 创建套接字，2.指向连接服务器
            if (!Create())
                return false;
            if (!Connect(ip, port))
                return false;
            return true;
        }
        // 设置套接字选项---开启地址端口重用
        void ReuseAddress()
        {
            // int setsockopt(int fd, int leve, int optname, void *val, int vallen)
            int val = 1;
            setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(int));
            val = 1;
            setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&val, sizeof(int));
        }
        // 设置套接字阻塞属性-- 设置为非阻塞
        void NonBlock()
        {
            // int fcntl(int fd, int cmd, ... /* arg );
            int fc = ::fcntl(_sockfd, F_GETFL);
            fc |= O_NONBLOCK;
            ::fcntl(_sockfd, F_SETFL, fc);
        }

        int Fd() { return _sockfd; }

        ~Socket()
        {
            if (_sockfd != -1)
                Close();
        }

    private:
        int _sockfd;
    };

    // 这是一个进行事件监控管理的模块
    class Poller;
    class Channel
    {
        using EventCallback = std::function<void()>; // 事件回调函数类型
    public:
        Channel(Poller *loop, int sockfd) : _loop(loop), _sockfd(sockfd), _events(0), _revents(0) {}

        int Fd() { return _sockfd; }

        u_int32_t Events() { return _events; }

        bool AbleRead() { return _events & EPOLLIN; }
        bool AbleWrite() { return _events & EPOLLOUT; }

        /// EventPool进行一次监控，触发的事件
        void setRevents(u_int32_t revents)
        {
            _revents = revents;
        }
        /// 开启读监控
        void enAbleread()
        {
            _events |= EPOLLIN;
            Update();
            return;
        }
        /// 开启写监控
        void enAblewrite()
        {
            _events |= EPOLLOUT;
            Update();
            return;
        }
        /// 关闭读监控
        void disAbleread()
        {
            _events &= ~EPOLLIN;
            Update();
            return;
        }
        /// 关闭写监控
        void disAblewrite()
        {
            _events &= ~EPOLLOUT;
            Update();
            return;
        }

        /// @brief 关闭所有事件监控
        void removeAllevents()
        {
            _events = 0;
            Update();
            return;
        }

        void Remove();
        void Update();

        void set_read_callback(const EventCallback &cb) { _read_callback = cb; }
        void set_write_callback(const EventCallback &cb) { _write_callback = cb; }
        void set_error_callback(const EventCallback &cb) { _error_callback = cb; }
        void set_close_callback(const EventCallback &cb) { _close_callback = cb; }
        void set_event_callback(const EventCallback &cb) { _event_callback = cb; }

        // 事件处理，一旦连接触发了事件，就调用这个函数，自己触发了什么事件如何处理自己决定
        void HandleEvent()
        {
            uint32_t revents = _revents;
            if ((revents & EPOLLIN) || (revents & EPOLLRDHUP) || (revents & EPOLLPRI))
            {
                if (_event_callback)
                    _event_callback();
                /*不管任何事件，都调用的回调函数*/
                if (_read_callback)
                    _read_callback();
            }
            /*有可能会释放连接的操作事件，一次只处理一个*/
            if (revents & EPOLLOUT)
            {
                if (_event_callback)
                    _event_callback();
                if (_write_callback)
                    _write_callback();
            }
            else if (revents & EPOLLERR)
            {
                if (_event_callback)
                    _event_callback();
                if (_error_callback)
                    _error_callback(); // 一旦出错，就会释放连接，因此要放到前边调用任意回调
            }
            else if (revents & EPOLLHUP)
            {
                if (_event_callback)
                    _event_callback();
                if (_close_callback)
                    _close_callback();
            }
            /// 任何事件都调用该接口_event_callback
        }
        ~Channel()
        {
        }

    private:
        u_int32_t _events;  // 进行监控的事件
        u_int32_t _revents; // 本次监控触发的事件
        Poller *_loop;      // Channel对应的EventLoop
        int _sockfd;        // Channel对应的sockfd

        EventCallback _read_callback;  // 可读事件被触发的回调函数
        EventCallback _write_callback; // 可写事件被触发的回调函数
        EventCallback _error_callback; // 错误事件被触发的回调函数
        EventCallback _close_callback; // 连接断开事件被触发的回调函数
        EventCallback _event_callback; // 任意事件被触发的回调函数
    };
// 这是一个监控模块，对文件描述符进行事件监控
#define MAX_EPOLLEVENTS 1024
    class Poller
    {
    private:
        int _epfd;
        struct epoll_event _evs[MAX_EPOLLEVENTS];
        std::unordered_map<int, Channel *> _channels;

    private:
        // 对epoll的直接操作
        void Update(Channel *channel, int op)
        {
            // int epoll_ctl(int epfd, int op,  int fd,  struct epoll_event *ev);
            int fd = channel->Fd();
            struct epoll_event ev;
            ev.data.fd = fd;
            ev.events = channel->Events();
            int ret = epoll_ctl(_epfd, op, fd, &ev);
            if (ret < 0)
            {
                ERR_LOG("EPOLLCTL FAILED!");
            }
            return;
        }
        // 判断一个Channel是否已经添加了事件监控
        bool HasChannel(Channel *channel)
        {
            auto it = _channels.find(channel->Fd());
            if (it == _channels.end())
            {
                return false;
            }
            return true;
        }

    public:
        Poller()
        {
            _epfd = epoll_create(MAX_EPOLLEVENTS);
            if (_epfd < 0)
            {
                ERR_LOG("EPOLL CREATE FAILED!!");
                abort(); // 退出程序
            }
        }
        // 添加或修改监控事件
        void UpdateEvent(Channel *channel)
        {
            bool ret = HasChannel(channel);
            if (ret == false)
            {
                // 不存在则添加
                _channels.insert(std::make_pair(channel->Fd(), channel));
                return Update(channel, EPOLL_CTL_ADD);
            }
            return Update(channel, EPOLL_CTL_MOD);
        }
        // 移除监控
        void RemoveEvent(Channel *channel)
        {
            auto it = _channels.find(channel->Fd());
            if (it != _channels.end())
            {
                _channels.erase(it);
            }
            Update(channel, EPOLL_CTL_DEL);
        }
        // 开始监控，返回活跃连接
        void Poll(std::vector<Channel *> *active)
        {
            // int epoll_wait(int epfd, struct epoll_event *evs, int maxevents, int timeout)
            int nfds = epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, -1);
            if (nfds < 0)
            {
                if (errno == EINTR)
                {
                    return;
                }
                ERR_LOG("EPOLL WAIT ERROR:%s\n", strerror(errno));
                abort(); // 退出程序
            }
            for (int i = 0; i < nfds; i++)
            {
                auto it = _channels.find(_evs[i].data.fd);
                assert(it != _channels.end());
                it->second->setRevents(_evs[i].events); // 设置实际就绪的事件
                active->push_back(it->second);
            }
            return;
        }
    };

    void Channel::Remove() { return _loop->RemoveEvent(this); }
    void Channel::Update() { return _loop->UpdateEvent(this); }
};

/// 1.0 version只提供最基础的Poller和Channel功能模块，为了方便测试